package asteroids.model.programs;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import be.kuleuven.cs.som.annotate.Basic;
import asteroids.model.Ship;
import asteroids.model.programs.parsing.expressions.E;
import asteroids.model.programs.parsing.statements.*;
import asteroids.model.programs.parsing.types.T;

public class Program {


	private List<S> allStatements;
	private int nbOfStatementsExecuted;
	private  int NbOfExecutes;
	private S lastStatementExecuted;
	private S nextStatement;
	private Map<String, T> map;
	private Sequence statement;
	private ExecuteManager executeManager;
	private Ship ship;


	public Program(Map<String, T> map, S s) {
		allStatements = new ArrayList<S>();
		setStatement(s);
		setAllStatements(getStatement());
		setMap(map);
		//              setVariables(map);
		setExecuteManager(new ExecuteManager(this));
		setFinished(false);
	}


	private void setVariables(Map<String, T> map, E expression) {


	}


	public void execute(){
		//              setNbOfExecutes(dt);                                    //Het aantal x dat een program kan uitgevoerd worden om 0.2 sec binnen dt
		//              int amountExecuted = 0;
		//              boolean test1 = amountExecuted < getNbOfExecutes();
		//              boolean test2 = amountExecuted<getNbOfStatements(getStatement());
		//              while(amountExecuted < getNbOfExecutes()  && amountExecuted<getNbOfStatements(getStatement())){
		//
		//                      S nextStatement = getNextStatement();
		//                      if(nextStatement != null){
		//                              nextStatement.execute(getExecuteManager());
		//                              setLastStatementExecuted(nextStatement);
		//                              
		//                      }
		//                      amountExecuted++;
		//              }
		if(!isFinished()){
			setActionDone(false);
			while(!isFinished() && !getActionDone() ){
				//				S nextStatement = getNextStatement();
				//				nextStatement.execute(getExecuteManager());
				//				increaseStatementsExecuted();
				getStatement().execute(getExecuteManager());
				if(getStatement().getExecuted()){
					setFinished(true);
				}

			}
		}


	}
	public boolean getActionDone(){
		return this.actionDone;
	}
	public void setActionDone(boolean actionDone){
		this.actionDone =actionDone;
	}
	private boolean actionDone = false;


	public void setAllStatements(Sequence sequence){
		List<S> statements = new ArrayList<S>();
		statements = sequence.getStatements();
		for(S statement: statements){
			if(statement.getClass() == sequence.getClass()){
				setAllStatements((Sequence)statement);
			}
			else{
				addStatement(statement);
			}
		}
	}




	public List<S> getAllStatements(){
		return this.allStatements;
	}


	public int getNbOfStatements(){
		//              int amount = 0;
		//              List<S> statements = new ArrayList<S>();
		//              statements = sequence.getStatements();
		//              for(S statement: statements){
		//                      if(statement.getClass() == sequence.getClass()){
		//                              amount+=getNbOfStatements((Sequence)statement);
		//                      }
		//                      else{
		//                              amount+=1;
		//                      }
		//              }
		//              System.out.println(amount);
		//              return amount;
		return getAllStatements().size();
	}

	public void addStatement(S s){
		allStatements.add(s);
	}
	public S getNextStatement(){
		return getAllStatements().get(getNbOfStatementsExecuted());
		//              S lastExecutedStatement = getLastStatementExecuted();
		//              S nextStatement = null;
		//              for(S statement: getStatement().getStatements()){
		//
		//                      if(lastExecutedStatement == null){
		//                              return statement;
		//                      }
		//                      else{
		//                              if(nextStatement!=null){
		//                                      if(statement.getLine() >  lastExecutedStatement.getLine()   &&  statement.getLine() < nextStatement.getLine()){ //dus de positie van statement is gelegen tussen de laatst uitgevoerde en de volgende
		//                                              nextStatement = statement;              
		//                                      }
		//                              }
		//                              else{
		//                                      if(statement.getLine() >  lastExecutedStatement.getLine()){
		//                                              nextStatement = statement;
		//                                      }
		//                              }
		//                      }
		//              }
		//              
		//              return nextStatement;


	}


	public void setFinished(boolean finished){
		this.finished = finished;
		if(finished = true){
			System.out.println("The program is finished, either there was a failure, or the program has run completly.");
			System.out.println("For further information please check the console.");
		}
	}


	public boolean isFinished(){
		return this.finished;
	}


	private boolean finished;


	public int getNbOfStatementsExecuted(){
		return this.nbOfStatementsExecuted;
	}


	private void increaseStatementsExecuted(){
		nbOfStatementsExecuted++;
	}


	public S getLastStatementExecuted(){
		return this.lastStatementExecuted;
	}




	public void setNextStatement(S statement){
		this.nextStatement = statement;
	}


	public void setLastStatementExecuted(S statement){
		this.lastStatementExecuted = statement;
	}


	public int getNbOfExecutes(){
		return this.NbOfExecutes;
	}
	private void setNbOfExecutes(double timeLapse) {
		double nbOfExMath       = timeLapse/0.2;
		int nbOfExShort         = (int) nbOfExMath;
		this.NbOfExecutes = nbOfExShort;
	}
	public void decreaseNbOfExecutes(){
		setNbOfExecutes(NbOfExecutes - 1);
	}
	@Basic
	public void setMap(Map<String, T> map){
		this.map = map;
	}


	@Basic
	public void setStatement(S statement){
		this.statement = (Sequence) statement;
	}


	@Basic
	public Map<String, T> getMap(){
		return this.map;
	}


	@Basic
	public Sequence getStatement(){
		return this.statement;
	}


	public void setShip(Ship ship){
		if((ship.getProgram() != this)){
			ship.setProgram(this);
		}
		this.ship =ship;
	}


	public Ship getShip(){
		return this.ship;               
	}


	public void setExecuteManager(ExecuteManager executeManager){
		this.executeManager = executeManager;
	}


	public ExecuteManager getExecuteManager(){
		return this.executeManager;
	}
	private boolean mistake;
	public boolean getMistake(){
		return this.mistake;
	}
	public void setMistake(){
		this.mistake =true;
		System.out.println("You've made a mistake in your syntax." +
				"This is what you were planning to do."); 
	}
}